<html>
    <head>
        <title>什么是函数式组件</title>
    </head>
    <body>
        <script>
            /*
               一、 什么是函数式组件？
                                    函数式组件在 Vue 官方定义为"无状态(没有响应式数据)，无实例(没有 this 上下文)"的组件。

                    */
                    /*
                        之前创建的锚点标题组件是"比较简单"，"没有管理任何状态"，也没有监听任何传递给它的状态，也没有生命周期方法。

                        实际上，它只是一个接受一些 prop 的函数。 

                        在这样的场景下，我们可以将组件"标记为" functional。这意味着它"无状态(没有响应式数据)"，也没有实例(没有 this 上下文)。
                    */
                    /*
                        一个"函数式组件"就像这样：
                    */
                    Vue.component('my-component',{
                        
                                functional:true, // 标记为函数式组件

                                // porps选项是可选的
                                props:{
                                    //...
                                },

                                /*
                                    为了弥补缺少的实例，
                                    函数式组件的渲染函数会额外接受第二个参数： context 作为上下文：
                                */ 
                                render:function(createElement,context){
                                    // ...
                                }
                            })

                    /*
                        注意： 在 2.3.0 之前的版本中，如果一个函数式组件想要接受props,则 props 选项时必须的。
                              在 2.3.0 或以上版本中，你可以省略 porps 选项，所有组件上的 atrribute 都会被自动隐式解析为 prop

                              当使用函数式组件时，该引用会是HTMLElement ,因为他们是无状态的也是无实例的。
                    */

                    /*
                        在 2.5.0 以及以上版本中，如果你使用了"单文件组件"，那么基于模板的函数式组件可以这样声明：

                            <template functional>

                            </template>
                    */

                    /*
                         函数式组件需要的一切都是通过 context 参数(上下文对象)传递的，它是一个包括如下字段的对象：

                                    props:  提供所以prop的对象
                                    children: VNode子字节的数组
                                    slots:  一个函数，返回了包含所有插槽的对象
                                    scopedSlots:  一个暴露传入的作用域插槽的对象。也以函数形式暴露普通插槽。
                                    data: 传递给组件的整个数据对象，作为 createElement 的第二个参数传入组件
                                    parent: 对父组件的引用
                                    listeners: (2.3.0+) 一包含了所有父组件为当前组件注册的事件监听器的对象。 这是 data.on 
                                    injections: 如果使用了 inject 选项，则该对象包含了应当被注入的property

                        在添加 functional:true 之后，需要更新我们的锚点标题组件的渲染函数，为其增加 context 参数，
                        并将 this.$slots.default更新为 context.children, 然后将this.level 更新为 context.props.level

                        因为函数式组件只是函数，所以渲染开销也低很多。

                        在作为包装组件时它们也同样非常有用。比如，当你需要做这些时：
                                1.程序化地在多个组件中选择一个来代为渲染：(那不就是类似冬天组件吗)
                                2.在将children 、 props、 data 传递给子组件之前操作它们。
                    */

                    // 下面是一个 smart-list 组件的例子，它能根据传入的 prop 值来代为渲染更具体的组件：
                                var EmptyList={/*....*/}
                                var TableList={/*....*/}
                                var OrderList={/*....*/}
                                var UnorderedList={/*....*/}

                                Vue.component('smat-list',{
                                    functional:true,
                                    props:{
                                        items:{
                                            type:Array,
                                            required:true
                                        },
                                        isOrdered:Boolean
                                    },
                                    render:function(createElement,context){
                                        function appropriateListComponent(){
                                            var items = context.props.items;

                                            if(items.length ===0) return EmptyList;

                                            if(typeof items[0] ==='object') return TableList;

                                            if(context.props.isOrdered) return OrderList;

                                            return UnorderedList;
                                        }

                                        return createElement(
                                            appropriateListComponent(),
                                            context.data,
                                            context.children
                                        )
                                    }
                                })
        </script>
    </body>
</html>